<?php
/***************************************************************************
 *                            class.pfCalendar.php
 *                            -------------------
 *   begin                : Apr 3 2012
 *   copyright            : GPL v2
 *   email                : info@mrmime.net
 *   author               : Emiliano Matarazzo
 *
 ***************************************************************************
 *                                 Comment
 *                            -------------------
 *  Managing data for Javascript calendar creation process
 *
 ***************************************************************************/

class pfCalendar extends pageContent
{
	protected $_yearyDays 			= null;
	protected $_yearMonths 			= null;
	protected $_weekDays 			= null;
	protected $_moonNumber			= null;
	protected $_beginYearDayNumber 	= null;
	protected $_yearDays			= null;
	protected $_dayDistribution 	= array();
	protected $_totalCalendar 		= array();

	protected $_contents			= null;
	protected $_calName				= null;

	protected $_daysNames			= array();
	protected $_monthsNames			= array();
	protected $_moons				= array();

	protected $_language			= null;
	protected $_error				= null;
	protected $_errorMessage		= null;
	protected $_fullMoons			= null;

	protected $_asList				= null;
	protected $_serialFileName		= null;

	function __construct($callName = null){
		global $calendarLanguage;
		parent::__construct();
		//Starting calendar with real file calendar data
		$this->_beginYearDayNumber = self::__firstDayOfYear();
		$this->_yearMonths = 12;
		$this->_weekDays   = 7;
		$this->_dayDistribution = array(31,self::__getFebraryDay(),31,30,31,30,31,31,30,31,30,31);
		$this->_yearDays = array_sum($this->_dayDistribution);
		$this->_calName   	= "sol";
		$this->_language	= $calendarLanguage;

		$this->_daysNames 	= $this->_language['daysNames'];
		$this->_monthsNames = $this->_language['monthsNames'];
		$this->_moons 		= array(array('name'=>$this->_language['moonName'],'month'=>1,'day'=>1));
		$this->_labels		= $this->_language['labels'];
		$this->_moonNumber  = 1;

		$this->_asList		= false;		
		
		$this->_contents = utf8_decode(file_get_contents(HTML_PATH.'calendar.html'));
	}
	
	private function __serialToData($serialData){
		$data = unserialize($serialData);
		$this->_calName 		= $data[0];
		$this->_weekDays 		= $data[1];
		$this->_yearMonths		= $data[2];
		$this->_beginYearDayNumber = $data[3];
		$this->_moonNumber		= $data[4];
		$this->_monthsNames		= self::__cleanUtf8($data[5]);
		$this->_dayDistribution	= $data[6];
		$this->_daysNames		= self::__cleanUtf8($data[7]);
		$this->_moons			= $data[8];
	}

	public function asList($asList){
		$this->_asList = $alList;
	}

	public function setData($data){
		$this->_calName 		= $data['calendarName'];
		$this->_weekDays 		= $data['weekDays'];
		$this->_yearMonths		= $data['yearMonths'];
		$this->_beginYearDayNumber = $data['beginYearDayNumber'];
		$this->_moonNumber		= $data['moonNumber'];
		$this->_monthsNames		= self::__cleanUtf8($data['monthsNames']);
		$this->_dayDistribution	= $data['dayDistribution'];
		$this->_daysNames		= self::__cleanUtf8($data['dayNames']);
		$this->_moons			= $data['moon'];
		
		$allInfo = serialize(array($this->_calName,
								   $this->_weekDays,
								   $this->_yearMonths,
								   $this->_beginYearDayNumber,
								   $this->_moonNumber,
								   $this->_monthsNames,
								   $this->_dayDistribution,
								   $this->_daysNames,
								   $this->_moons));
		$this->_serialFileName = date('Y-m-d-h.i.s_').$this->_calName.'.txt';						   
		file_put_contents(STORE_PATH.$this->_serialFileName,$allInfo);
	}

	private function __translate($content){
		$translator = new pfTranslator();
		$translator->setContent($content);
		$translator->translateCalendar();
		return $translator->getContent();		
	}

	private function __firstDayOfYear(){
		return date('N',mktime(0,0,0,1,1,date('Y')))-1;
	}

	private function __getFebraryDay($year = null){
		$year = (is_null($year)) ? date('Y'):$year;
		return (checkdate(2,29,$year)) ? 29 : 28;
	}
	 
	public function manageVisible(){
		//TODO: da valutare
		if ($this->_visibileContent == "")
			$this->_visibileContent = self::buildSheet();
	}
	
	private function __loadCalendar(){
		
	}
	 
	public function manageAction($data){
		$upload = new uploadManager();
		$tmpPath = STORE_PATH.'/loaded/';
		$tmpFile = time().'.txt';
		$upload->setObjectOutput('serialdatafile', $tmpPath,$tmpFile);
		$upload->manageFiles($_FILES);
		
		if (file_exists($tmpPath.$tmpFile)){
			self::__serialToData(file_get_contents($tmpPath.$tmpFile));
			return;
		}
		
		//If Im loading a previous calendar
		if (isset($data['serialdata'])){
			self::__serialToData($data['serialdata']);
			return;
		}
		
		//If Im creating a new one
		if (empty($data["weekDays"]) || empty($data["yearMonths"]) || empty($data['calendarName'])){
			$this->_errorContent = "manca roba";
			$this->_error = true;
		}
		else {
			$this->_asList = $data['orientation'];
			self::setData($data);
			$cc = self::buildCalendar();
			$now = date ("Ymd");
			$cName = $now.$data['calendarName'];
			$totalCode = $printCode = "";
			foreach ($cc as $index=>$month){
				$totalCode .= '<div style="position:relative;width:100%;float:left;">'.$month.'</div>';
				$fName = $cName.'_'.($index+1).'.html';
				file_put_contents('./store/calendars/'.$cName.'_'.($index+1).'.html', self::__translate($month));
				$printCode .= '<div style="width:100%;float:left;"><a href="'.STORE_PATH.'/calendars/'.$fName.'"/>'.$month.'</a></div><br />';
			}
			$this->_visibileContent = '<div><a href="'.STORE_PATH.$this->_serialFileName.'" >SCARICA CODICE</a><div>';
			$this->_visibileContent .= $printCode;
			$this->_visibileContent =  self::__translate($this->_visibileContent);
		}
	}
	 
	/**
	 * Building form page
	 */
	public function buildSheet(){
		$this->_contents = str_replace('[[error]]',$this->_erroMessage,$this->_contents);

		$this->_contents = str_replace('[[calName]]',$this->_calName,$this->_contents);
		$this->_contents = str_replace('[[yearDays]]',$this->_yearDays,$this->_contents);
		$this->_contents = str_replace('[[yearMonths]]',$this->_yearMonths,$this->_contents);
		$this->_contents = str_replace('[[weekDays]]',$this->_weekDays,$this->_contents);
		$this->_contents = str_replace('[[moonNumber]]',$this->_moonNumber,$this->_contents);
		$this->_contents = str_replace('[[beginYearDayNumber]]',$this->_beginYearDayNumber,$this->_contents);

		$this->_contents = str_replace('[[days]]',self::__buildDaysList(),$this->_contents);
		$this->_contents = str_replace('[[months]]',self::__buildMonthsList(),$this->_contents);
		$this->_contents = str_replace('[[moons]]',self::__buildMoonsList(),$this->_contents);

		$this->_contents = self::__translate($this->_contents);
		
		return $this->_contents;
	}
	 
	/**
	 * Bulding day list inputs
	 */
	private function __buildDaysList(){
		$table = new simpleTable();
		$table->showForm(false);
		$table->setCellspacing(1);
		$table->setCellpadding(1);
		$table->setLabels(array('n.','name'));
		
		$code 	= new textCell();
		$name	= new textCell();
		
		$jsCode 	= "";
		$htmlCode 	= "";
		foreach ($this->_daysNames as $index=>$dayName){
			$jsCode[] = "'".utf8_decode($dayName)."'";
			$code->setValue('<input type="text" readonly="readonly" size="1" value="'.$index.'" />');
			$name->setValue('<input type="text" id="dayName'.$index.'" name="dayNames['.$index.']" onKeyUp="javascript:dayNames['.$index.'] = this.value;" value="'.utf8_decode($dayName).'" />');
			$table->addRow(array($code,$name));
		}

		$htmlCode = $table->getCode();
		$htmlCode .='<script>
						dayNames = new Array('.implode(",",$jsCode).');
						totalDays = '.count($days).';
					  </script>';
		return $htmlCode;
	}
	 
	/**
	 * Building moon lista inputs
	 */
	private function __buildMoonsList(){
		$jsCode 	= "";
		
		$table = new simpleTable();
		$table->showForm(false);
		$table->setCellspacing(1);
		$table->setCellpadding(1);
		$table->setLabels(array('{name}','{full_month}','{full_day}'));
		
		$month 	= new textCell();
		$month->setAlign("center");
		$day 	= new textCell();
		$day->setAlign("center");
		$name	= new textCell();
		
		foreach ($this->_moons as $index=>$moonInfo){
			$jsCode[] = "'".utf8_decode($moonInfo['name'])."'";
			$name->setValue('<input type="text" id="moonName'.$index.'" name="moon['.$index.'][name]" value="'.utf8_decode($moonInfo['name']).'" size="5" 	onKeyUp="javascript:moonsNames['.$index.'] 		= this.value;" />');
			$month->setValue('<input type="text" id="monthWithFullMoon'.$index.'" name="moon['.$index.'][month]" 	size="2" value="'.$moonInfo['month'].'" onKeyUp="javascript:monthFullMoon['.$index.'] 	= this.value;" />');
			$day->setValue('<input type="text" id="dayWithFullMoon'.$index.'" name="moon['.$index.'][day]" 		size="2" value="'.$moonInfo['day'].'" 	onKeyUp="javascript:dayFullMonth['.$index.'] 	= this.value;" />');
			$table->addRow(array($name,$month,$day));
		}

		$htmlCode = $table->getCode();
		$htmlCode .='<script>
						moonsNames 	= new Array('.implode(",",$jsCode).');
						totalMoons 	= '.count($days).';
					  </script>';
		return $htmlCode;
	}
	 
	/**
	 * Building months list inputs
	 */
	private function __buildMonthsList(){
		$jsCode  = "";
		$jsCode2 = "";
		
		$table = new simpleTable();
		$table->showForm(false);
		$table->setCellspacing(1);
		$table->setCellpadding(1);
		$table->setLabels(array('n.','name','days'));
		
		$name	= new textCell();
		$code	= new textCell();
		$days	= new textCell();
		
		foreach ($this->_monthsNames as $index=>$monthName){
			$jsCode[] 	= $this->_dayDistribution[$index];
			$jsCode2[]	= "'".$monthName."'";
			
			$code->setValue('<input type="text" readonly="readonly" size="1" value="'.$index.'" />');
			$name->setValue('<input type="text" name="monthsNames['.$index.']" value="'.$monthName.'" onKeyUp="javascript:monthsNames['.$index.'] = this.value;" />');
			$days->setValue('<input type="text" size="3" name="dayDistribution['.$index.']" value="'.$this->_dayDistribution[$index].'" onKeyUp="javascript:dayDistribution['.$index.'] = parseInt(this.value); totalYearDays();" />');
			$table->addRow(array($code,$name,$days));			
		}

		$htmlCode = $table->getCode();
		$htmlCode .= ' <script>
							monthNames 		= new Array('.implode(",",$jsCode2).');
							dayDistribution = new Array('.implode(",",$jsCode).');
							totalMonthNumber = '.count($month).';
							totalYearDays();
						  </script>';
		return $htmlCode;
	}
	 
	 
	/**
	 * Method to calculate total number of days from start of the year
	 * @param month of final day
	 * @param day inside month
	 * @return sum of day of every month before month plus day
	 * Es.
	 * month = 3 (march)
	 * day = 10
	 * value = 31 (gen) + 28 (feb) + 10 
	 */
	private function __getDayNumberFromStart($month,$day){
		if ($month-1 == 0){
			return $day;
		}
		$chunck = array_chunk($this->_dayDistribution,--$month);
		$days = array_sum($chunck[0]) + $day;
		return $days;
	}
	
	private function __getAllFullMoons($moons){
		foreach ($moons as $moonInfo){
			$days = self::__getDayNumberFromStart($moonInfo['month'], $moonInfo['day']);
			$start = $days % 30;
			$this->_fullMoons[$start] = $moonInfo['name'];
			while (($start+30) < $this->_yearDays){
				$start += 30;
				$this->_fullMoons[$start] = $moonInfo['name'];
			}
		}
	}
	 
	 
	//***********************************************************************//
	public function buildCalendar(){
		$monthDayAverage 	= floor($this->_yearDays / $this->_yearMonths);
		$dayRest 			= $this->_yearDays - ($monthDayAverage * $this->_yearMonths);
		$yearWeeks 			= floor( $this->_yearDays / $this->_weekDays);
		$weekRest  			= $this->_yearyDays - ($yearWeeks * $this->_weekDays);
		self::__getAllFullMoons($this->_moons);

		$numberBeginMonth = array(1);
		$daySumTemp		  = array(1);
		foreach ($this->_dayDistribution as $index=>$mDayNumbers){
			if ($index == ($this->_yearMonths-1)) break;
			$numberBeginMonth[] = array_sum($daySumTemp)+$mDayNumbers;
			$daySumTemp[] = $mDayNumbers;
		}

		$totalCalendar = array();
		for ($i=1,$currentMonth=0,$j=$this->_beginYearDayNumber-1,$currentMonthDay = 0,$beginMonthWeekDay=$this->_beginYearDayNumber,$totalDay = 1;$i<$this->_yearDays;$i++,$totalDay++){
			if ($i == $numberBeginMonth[$currentMonth+1]){
				$currentMonth++;
				$currentMonthDay = 0;
				$beginMonthWeekDay = self::__seekFirstDay($this->_dayDistribution,$currentMonth,$this->_beginYearDayNumber,$this->_weekDays);
			}
			$totalCalendar[$this->_monthsNames[$currentMonth]][$i]['dayName'] 	 	= $this->_daysNames[++$j%count($this->_daysNames)];
			$totalCalendar[$this->_monthsNames[$currentMonth]][$i]['dayNumber'] 	= ++$currentMonthDay;
			$totalCalendar[$this->_monthsNames[$currentMonth]][$i]['dayInWeek'] 	= $beginMonthWeekDay;
			$totalCalendar[$this->_monthsNames[$currentMonth]][$i]['fullMoon'] 		= 0;
			if (array_key_exists($totalDay,$this->_fullMoons))
				$totalCalendar[$this->_monthsNames[$currentMonth]][$i]['fullMoon'] 		= 1;
			$beginMonthWeekDay = ($beginMonthWeekDay+1)%$this->_weekDays;
		}

		return self::__buildCalendarCode($totalCalendar);
	}
	 
	private function __buildCalendarCode($totalCalendar){
		if ($this->_asList){
			return self::__buildAsList($totalCalendar);
		}
		else {
			return self::__buildAsTable($totalCalendar);
		}
	}
	 
	private function __buildAsList($totalCalendar){
		$monthTables =  file_get_contents(HTML_PATH.'monthsTable.html');

		$headRowCode = "<th style=\"width:50px;\">N</th>\n<th style=\"width:100px;\">{name}</th>\n<th style=\"width:600px;\">{note}</th>\n
  						";
		$monthTables =  str_replace ('[[head_cells]]',$headRowCode,$monthTables);

		$finalCalendar 	= array();

		foreach ($totalCalendar as $monthName=>$days){
			$rowsTemplate = "<tr>[[columns]]<tr>\n";
			$monthRows 		= array();
			foreach ($days as $dayInfo){
				$fullMoon = ($dayInfo['fullMoon']) ? '()':'';
				$cols = "<td>".$dayInfo['dayNumber']."</td>\n<td>".utf8_decode($dayInfo['dayName'])." ".$fullMoon."</td>\n<td>&nbsp;</td>\n";

				$monthRows[] = str_replace ('[[columns]]',$cols,$rowsTemplate);
			}
			$finalCalendar[] = str_replace('[[monthName]]',utf8_decode($monthName),str_replace ('[[rows]]',implode($monthRows),$monthTables));
		}
		return $finalCalendar;
	}
	 
	private function __buildAsTable($totalCalendar){
		$monthTables = file_get_contents(HTML_PATH.'monthsTable.html');
			
		$headRowCode = "";
		foreach ($this->_daysNames as $index=>$dayName){
			$headRowCode .='<th style="width_100px">'.utf8_decode($dayName).'</th>';
		}

		$monthTables =  str_replace ('[[head_cells]]',$headRowCode,$monthTables);

		$finalCalendar = array();

		foreach ($totalCalendar as $monthName=>$days){
			$monthIndex = array_search($monthName, $this->_monthsNames);
			$currentMonthDays  =  $this->_dayDistribution[$monthIndex];
			$totalMonthRow = ceil($currentMonthDays / $this->_weekDays);
			$rowsTemplate = '<tr>[[columns]]<tr>';

			$dayIndexInit = self::__seekFirstDay($this->_dayDistribution, $monthIndex, $this->_beginYearDayNumber, $this->_weekDays);
			$lastDay 	  = self::__seekLastDay ($this->_dayDistribution[$monthIndex],$dayIndexInit,$this->_weekDays);
			$allSundays   = self::__seedAllSunday($this->_dayDistribution[$monthIndex],$dayIndexInit,$this->_weekDays);

			$monthRows = array();
			$columns   = array();

			foreach ($days as $singleDay){
				$dayNumber = $singleDay['dayNumber'];
				//Se è diverso da zero, allora il mese inizia non il primo
				//giorno della settimana
				if ($dayIndexInit != 0 && $dayNumber == 1){
					$columns[] = '<td colspan="'.$dayIndexInit.'" class="spanned">&nbsp;</td>';
				}
				$columns[] = '<td>'.$dayNumber.'</td>';
				if (in_array($dayNumber,$allSundays)){
					$monthRows[] = str_replace ('[[columns]]',implode($columns),$rowsTemplate);
					$columns = array();
				}
			}
			if ($singleDay['dayInWeek'] != $weekDays-1)
			$columns[] = '<td colspan="'.($weekDays-$singleDay['dayInWeek']-1).'" class="spanned">&nbsp;</td>';
			$monthRows[] = str_replace ('[[columns]]',implode($columns),$rowsTemplate);
			$finalCalendar[] = str_replace('[[monthName]]',utf8_decode($monthName),str_replace ('[[rows]]',implode($monthRows),$monthTables));
		}
		return $finalCalendar;
	}
	 
	//Dato un numero di giorni in un mese, il giorno di partenza nella settimanaa
	//ed i giorni in una settimana, ritorna il giorno della settimana dell'ultimo del mese
	private function __seekLastDay($monthDays,$weekStartDay,$weekDays){
		return $weekStartDay+($monthDays%$weekDays-1);
	}

	private function __seekFirstDay($dayDistribution,$month,$firstDayOfYear,$weekDay){
		if ($month == 0) return $firstDayOfYear;
		$previousInitDay = $firstDayOfYear;
		foreach ($dayDistribution as $monthIndex=>$days){
			if ($monthIndex == $month) return $previousInitDay;
			$lastDay = self::__seekLastDay($days, $previousInitDay, $weekDay);
			$previousInitDay = ($lastDay+1) % $weekDay;
		}
	}

	private function __seedAllSunday($monthDays,$weekBeginDay,$weekDays){
		$sundays = array();
		$firstSunday = $weekDays - $weekBeginDay;
		//$sundays[] = $firstSunday;
		for ($s=$firstSunday;$s<$monthDays;$s+=$weekDays)
		$sundays[] = $s;
		return $sundays;
	}
	 
}

?>
